home *** CD-ROM | disk | FTP | other *** search
- /* nstat - network statistics collector
- *
- * nstat [-i interface][-t time period (sec)]
- */
-
- #include <stdio.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <malloc.h>
- #include <errno.h>
- #include <time.h>
-
- #include <sys/file.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <sys/stropts.h>
- #include <net/if.h>
- #include <net/nit.h>
- #include <net/nit_if.h>
- #include <net/nit_buf.h>
- #include <netinet/in.h>
- #include <netinet/if_ether.h>
-
- #define MAX_CHUNK 1024*100 /* maximum chunk size returned */
- #define TIMEOUT 2 /* chunk timeout in seconds */
- #define MAX_DATA_LEN 60
- #define PKT_TIMESTAMPS 0x1 /* packet headers contain timestamps */
- #define PKT_HEADERS 0x2 /* packets contain network-layer headers */
- #define DEBUG 0
-
- struct nit_packet {
- struct nit_bufhdr header;
- u_long nit_if_drops,
- nit_if_origlen;
- struct pkt { /* simplified - ignores option fields */
- /* ethernet */
- u_char edst[6];
- u_char esrc[6];
- u_short etype;
- /* IP */
- u_char vl;
- u_char tos;
- u_short tlen;
- u_short ident;
- u_short foff;
- u_char time;
- u_char proto;
- u_short ipcksum;
- u_char isrc[4];/* can't use long, for alignment - sigh */
- u_char idst[4];/* can't use long, for alignment - sigh */
- /* tcp */
- u_short tsrc;
- u_short tdst;
- u_char seq[4]; /* can't use long, for alignment - sigh */
- u_char ack[4]; /* can't use long, for alignment - sigh */
- u_char ofr;
- u_char code;
- u_short window;
- u_short tcpcksum;
- u_short urg;
- u_char data[1];
- } pkt;
- };
-
- u_char *buffer;
- u_long *etypep, *udpportp, *tcpportp;
- u_long *etypeb, *udpportb, *tcpportb;
- u_long *ipprotop, *ipprotob;
- u_long ipoptions = 0;
- u_long total = 0;
- u_long totalb = 0;
- u_long n802 = 0;
- u_long runt = 0;
- u_long dropped = 0;
- u_long cur_drop = 0;
- int nit;
- int promiscuous = 1;
- char interface[10] = "le0";
- int set_time = 3600;
- struct timeval starttimer, stoptimer;
- int debug = DEBUG;
-
- void init();
- void cleanup ();
- void report();
- void collect ();
- void setoptions ();
- void usage ();
- void dump_pkt();
-
- /* Main routine setup everything, then call collect */
- main (argc,argv)
- int argc;
- char **argv;
- {
- setoptions(argc,argv);
- init();
- nit = insert_tap(interface);
- signal(SIGINT,cleanup);
- collect(); /* does not return */
- }
-
- void setoptions (argc,argv)
- int argc;
- char **argv;
- {
- if(argc==2)
- usage("argc = 2");
- while(argc>2) {
- if(argv[argc-2][0]!='-')
- usage("argv missing -");
- switch(argv[argc-2][1]){
- case 'i': {strcpy(interface,argv[argc-1]);
- break;}
- case 't': {set_time = atoi(argv[argc-1]);
- break;}
- default : {usage("bad switch");}
- }
- argc -= 2;
- }
- }
-
- void usage (e)
- char *e;
- {
- fprintf(stderr,"%s\n",e);
- fputs("Usage: nstat \n",stderr);
- fputs(" [-i interface]\t(default \"le0\")\n",stderr);
- fputs(" [-t set_secs]\t(default 3600)\n",stderr);
- exit (1);
- }
-
- void init()
- {
- buffer = (u_char *)calloc((unsigned)(MAX_CHUNK), sizeof(char));
- etypep = (u_long *)calloc((unsigned)65536,sizeof(u_long));
- etypeb = (u_long *)calloc((unsigned)65536,sizeof(u_long));
- tcpportp = (u_long *)calloc((unsigned)65536,sizeof(u_long));
- tcpportb = (u_long *)calloc((unsigned)65536,sizeof(u_long));
- udpportp = (u_long *)calloc((unsigned)65536,sizeof(u_long));
- udpportb = (u_long *)calloc((unsigned)65536,sizeof(u_long));
- ipprotop = (u_long *)calloc((unsigned)256,sizeof(u_long));
- ipprotob = (u_long *)calloc((unsigned)256,sizeof(u_long));
- }
-
- /* Insert tap - setup NIT socket */
- int insert_tap (if_name)
- char *if_name;
- {
- int if_fd;
- u_long tempval;
- u_int temp2;
- struct strioctl si;
- struct ifreq ifr;
- struct timeval timeout;
-
- if ((if_fd = open("/dev/nit", O_RDONLY)) < 0) {
- perror ("opening nit stream");
- exit (1);
- }
- /* Arrange to get discrete messages from the stream */
- if (ioctl( if_fd, I_SRDOPT, (char *)RMSGD) != 0) {
- perror("I_SRDOPT");
- exit (1);
- }
- /* Push and configure NIT buffering module */
- if (ioctl(if_fd, I_PUSH, "nbuf") != 0) {
- perror("I_PUSH nbuf");
- exit (1);
- }
-
- si.ic_timout = INFTIM;
- timeout.tv_sec = (long)(TIMEOUT);
- timeout.tv_usec = 0;
- si.ic_cmd = NIOCSTIME;
- si.ic_len = sizeof timeout;
- si.ic_dp = (char *)&timeout;
- if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
- perror("NIOCSTIME");
- exit (1);
- }
- si.ic_cmd = NIOCSCHUNK;
- temp2 = (u_int)(MAX_CHUNK);
- si.ic_len = sizeof temp2;
- si.ic_dp = (char *)&temp2;
- if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
- perror("NIOCSCHUNK");
- exit (1);
- }
- /* Configure the NIT device, binding it to the proper interface */
- strncpy (ifr.ifr_name, if_name, sizeof (ifr.ifr_name));
- ifr.ifr_name[sizeof ifr.ifr_name -1] = ' ';
- si.ic_cmd = NIOCBIND;
- si.ic_len = sizeof ifr;
- si.ic_dp = (char *)𝔦
- if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
- perror(": NIOCSBIND");
- exit (1);
- }
-
- /* Set snapshot length */
- /* currently commented out, as it causes the machine to hang!!!
- * tempval = (u_long) (MAX_DATA_LEN);
- * si.ic_cmd = NIOCSSNAP;
- * si.ic_len = sizeof tempval;
- * si.ic_dp = (char *)&tempval;
- * if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
- * perror("NIOCSSNAP");
- * exit (1);
- * }
- */
-
- tempval = NI_DROPS | NI_LEN;
- if (promiscuous)
- tempval |= NI_PROMISC;
- si.ic_cmd = NIOCSFLAGS;
- si.ic_len = sizeof tempval;
- si.ic_dp = (char *)&tempval;
- if (ioctl(if_fd, I_STR, (char *)&si) !=0) {
- perror("NIOCSFLAGS");
- exit(1);
- }
- ioctl(if_fd, I_FLUSH, (char *)FLUSHR);
- return if_fd;
- }
-
- void collect ()
- {
- register unsigned char *bp;
- register unsigned char *bufend;
- register struct nit_packet *hdrp;
- int tail;
- int plen,nlen;
-
- gettimeofday (&starttimer, (struct timezone *)NULL);
- while (1) {
- while ((tail = read(nit,buffer, MAX_CHUNK)) <= 0);
- bp = buffer;
- bufend = bp + tail;
- while (bp < bufend) {
- hdrp = (struct nit_packet *)bp;
- plen = hdrp->header.nhb_msglen;
- nlen = hdrp->header.nhb_totlen;
- bp += nlen;
- if(plen >= MAX_DATA_LEN+8)
- countpacket(hdrp);
- else
- runt++;
- }
- gettimeofday (&stoptimer, (struct timezone *)NULL);
- if ( (stoptimer.tv_sec - starttimer.tv_sec) > set_time) {
- report();
- gettimeofday(&starttimer, (struct timezone *) NULL);
- }
-
- }
- }
-
- countpacket(p)
- struct nit_packet *p;
- {
- int ipoptlen;
- cur_drop = p -> nit_if_drops - dropped;
- total++;
- totalb += p->nit_if_origlen;
- if(p->pkt.etype <1515) {
- n802++;
- return;
- }
- if(debug)
- dump_pkt((char *)&(p->pkt));
- etypep[p->pkt.etype]++;
- etypeb[p->pkt.etype] += p->nit_if_origlen;
- if(p->pkt.etype == ETHERTYPE_IP) {
- ipprotop[(unsigned int)p->pkt.proto]++;
- ipprotob[(unsigned int)p->pkt.proto] += p->nit_if_origlen;
- ipoptlen = (((p->pkt.vl)&0x0f)-5)*2;
- if(ipoptlen != 0) {
- ipoptions++;
- printf("# ipoptlen %d\n",ipoptlen);
- }
-
- if (p->pkt.proto == IPPROTO_TCP) {
- tcpportp[*(&(p->pkt.tsrc)+ipoptlen)]++;
- tcpportp[*(&(p->pkt.tdst)+ipoptlen)]++;
- tcpportb[*(&(p->pkt.tsrc)+ipoptlen)] += p->nit_if_origlen;
- tcpportb[*(&(p->pkt.tdst)+ipoptlen)] += p->nit_if_origlen;
- }
- else if (p->pkt.proto == IPPROTO_UDP){
- udpportp[*(&(p->pkt.tsrc)+ipoptlen)]++;
- udpportp[*(&(p->pkt.tdst)+ipoptlen)]++;
- udpportb[*(&(p->pkt.tsrc)+ipoptlen)] += p->nit_if_origlen;
- udpportb[*(&(p->pkt.tdst)+ipoptlen)] += p->nit_if_origlen;
- }
- }
- }
-
- void report()
- {
- int i;
- char t1[40],t2[40];
-
- strcpy(t1,ctime(&starttimer.tv_sec));
- strcpy(t2,ctime(&stoptimer.tv_sec));
- printf ("#Start %s#Stop %s",t1,t2);
- printf("#%lu packets, %lu bytes, %lu 802.3, %lu runt, %lu missed, %lu ipopt.\n",
- total, totalb, n802, runt, cur_drop,ipoptions);
- total = 0;
- totalb = 0;
- n802 = 0;
- runt = 0;
- ipoptions = 0;
- dropped += cur_drop;
-
- for(i=0;i<65536;i++) {
- if(etypep[i]>0){
- printf("e %x\t# %lu\tb %lu\n",i,
- etypep[i],etypeb[i]);
- etypep[i] = 0;
- etypeb[i] = 0;
- }
- }
- for(i=0;i<256;i++) {
- if(ipprotop[i] >0) {
- printf("i %d\t# %lu\tb %lu\n",i,
- ipprotop[i],ipprotob[i]);
- ipprotop[i] = 0;
- ipprotob[i] = 0;
- }
- }
- for(i=0;i<65536;i++) {
- if(tcpportp[i]>0) {
- printf("t %d\t# %lu\tb %lu\n",i,
- tcpportp[i],tcpportb[i]);
- tcpportp[i] = 0;
- tcpportb[i] = 0;
- }
- }
- for(i=0;i<65536;i++) {
- if(udpportp[i]>0) {
- printf("u %d\t# %lu\tb %lu\n",i,
- udpportp[i],udpportb[i]);
- udpportp[i] = 0;
- udpportb[i] = 0;
- }
- }
- fflush(stdout);
- }
-
-
- void cleanup ()
- {
- close (nit);
- report();
- exit (0);
- }
-
- void dump_pkt(b)
- char *b;
- {
- char s[32],d[32];
- int i1,i2;
- struct pkt *p;
- extern char *ether_ntoa();
- extern char *inet_ntoa();
-
- p = (struct pkt *) b;
-
- strcpy(s, ether_ntoa((struct ether_addr *) p->esrc));
- strcpy(d, ether_ntoa((struct ether_addr *) p->edst));
- printf("Ethernet src %s dst %s type %d\n",s,d,p->etype);
-
- strcpy(s, inet_ntoa((struct inet_addr *) p->isrc));
- strcpy(d, inet_ntoa((struct inet_addr *) p->idst));
- printf("IP src %s dst %s length %d ident %d\n",
- s,d, (int) p->tlen, (int) p->ident);
-
- bcopy(p->seq,&i1,4);
- bcopy(p->ack,&i2,4);
- printf("TCP src port %d dst port %d seq %d ack %d\n",
- (int)p->tsrc, (int)p->tdst, i1, i2);
- printf("Code %d Data 0x%x\n",(int)p->code,(int)p->data[0]);
- }
-